Criminaliteit en Welvaart#
Student names: Chris Dukker, David Snoeks, Ryan Rodrigus, Jason Roes
Team number: D2
# Load image from link
url = 'https://ccv-secondant.nl/fileadmin/w/secondant_nl/platform/illustraties/Internationaal.jpg'
# Display image from URL with smaller size and subtitle
from IPython.display import Image, display
# Set the desired image width and height
width = 600
height = 300
# Set the subtitle text
#subtitle = "© CCV / Hans Sprangers"
# Create an Image instance with the URL
image = Image(url=url, width=width, height=height)
# Display the image and subtitle
display(image)
#print(subtitle)

Introduction#
Europa is, over het algemeen genomen, welvarend. Meerdere van de sterkste economieën op aarde bevinden zich op dit continent, en de EU kan zich in economische termen meten aan andere grootmachten. Deze welvaart is alleen niet gelijkmatig verdeeld. Sommige landen zijn welvarender dan andere, maar ook binnen de landen bestaat er economische ongelijkheid doordat de welvaart verschillend is verdeeld. Ook zijn er verscillen in de criminaliteit. Landen hebben te kampen met verschillende hoeveelheden misdaad, en niet ieder land heeft last van dezelfde soorten criminaliteit. De vraag waar wij ons in dit datastory mee bezig houden is: is er een verband te vinden in (de verdeling van) welvaart van een land, en de hoeveelheid illegale activiteit in dit land?
Met deze data story onderzoeken wij of welvaartsongelijkheid en het gemiddelde inkomen per persoon invloed hebben op de hoeveelheid gepleegde misdaden, en of deze variabelen een sterkere correlatie vertonen met bepaalde categorieën misdaad zoals moord, verkrachting, diefstal en fraude. Dit doen we met behulp van gegevens van World Bank Group over de GINI-coëfficient (een maatstaf voor inkomens- of vermogenongelijkheid) en economische statistieken en groei dataset van World Bank Open Data en de misdaadstatistieken dataset van Eurostat.
Hieronder kan geschrapt worden?
Volgens De Courson & Nettle (2021) is voor mensen met een laag inkomen en kapitaal de criminaliteit de beste manier om hun kwaliteit van leven te verbeteren. Hoewel er het risico is om gepakt te worden, is de mogelijke winst bij succes dit risico waard. Vanwege het kleine toekomstperspectief is misdaad voor deze bevolkingsgroep de beste manier om hun leven te verbeteren. Volgens ditzelfde onderzoek leidt een grote ongelijkheid tot meer criminaliteit, terwijl een eerlijkere verdeling van welvaart positieve effecten heeft en de mogelijke voordelen van misdaad verkleint.
Meer misdaad door welvaartsongelijkheid#
Bla bla, Criminaliteit en welvaart (ongelijkheid) hebben een sterk verband, want de argumenten hier onder.
Verband diefstal, fraude en ongelijkheid#
Correlatie 1 met grafiek
import pandas as pd
import plotly.express as px
import numpy as np
# === Load Data ===
# Crime dataset
crime_df = pd.read_csv("europe_crime_definitive_absolute.csv")
# World Bank economic dataset
econ_df = pd.read_csv("world_bank_definitive.csv")
# === Filter and Preprocess ===
# Desired economic indicators
selected_indicators = [
"GDP, PPP (constant 2021 international $)",
"Gross national expenditure (current US$)",
"Imports of goods and services (current US$)",
"Total reserves (includes gold, current US$)",
"GNI per capita growth (annual %)",
"Inflation, consumer prices (annual %)"
]
# Filter econ_df for selected indicators
econ_filtered = econ_df[econ_df["Indicator Name"].isin(selected_indicators)]
# Pivot so each indicator becomes a column
econ_pivot = econ_filtered.pivot_table(
index=["Country Name", "Year"],
columns="Indicator Name",
values="Value"
).reset_index()
# Rename columns for convenience
econ_pivot.columns.name = None
# Prepare crime data
crime_df.rename(columns={
'Geopolitical entity (reporting)': 'Country Name',
'TIME_PERIOD': 'Year'
}, inplace=True)
crime_df['Year'] = pd.to_numeric(crime_df['Year'], errors='coerce')
# Merge on Country and Year
merged_df = pd.merge(econ_pivot, crime_df, on=['Country Name', 'Year'])
# Drop rows with missing values
merged_df.dropna(inplace=True)
# Extract actual column names
econ_cols = selected_indicators
crime_cols = [col for col in crime_df.columns if col not in ['Country Name', 'Year'] and col in merged_df.columns]
# Subset relevant columns
corr_data = merged_df[econ_cols + crime_cols].select_dtypes(include=[np.number])
# Recalculate available econ and crime columns (since some might have been dropped)
econ_cols_numeric = [col for col in econ_cols if col in corr_data.columns]
crime_cols_numeric = [col for col in crime_cols if col in corr_data.columns]
# Compute correlation matrix
correlation_matrix = corr_data.corr()
econ_crime_corr = correlation_matrix.loc[econ_cols_numeric, crime_cols_numeric]
# === Plot Heatmap ===
fig = px.imshow(
econ_crime_corr,
labels=dict(x="Crime Indicators", y="Economic Indicators", color="Correlation"),
x=econ_crime_corr.columns,
y=econ_crime_corr.index,
color_continuous_scale="RdBu",
zmin=-1, zmax=1,
)
fig.update_layout(title="Correlation Between Selected Economic and Crime Indicators")
fig.show()
b
Figure 2: dd
blabla
The Second Argument of Your First Perspective#
bla bla
Show code cell source
import plotly.graph_objects as go
import pandas as pd
Figure 3:
blabla
Your Second Perspective#
Bla bla, Criminaliteit en welvaart (ongelijkheid) hebben geen sterk verband/ er zijn belangrijke factoren, want de argumenten hier onder.
The First Argument of Your Second Perspective#
Hoewel je misschien zou denken dat er in armere landen meer misdaden gebeuren, voornamelijk diefstal, wat het grootste deel van het aantal gerapporteerde misdaden uitmaakt, is dit juist niet het geval. Toen we onze dataset analyseerden vonden we juist dat over het algemeen hoe rijker een land is, hoe groter het totaal aantal gerapporteerde misdaden is.
Show code cell source
import pandas as pd
import plotly.express as px
import statsmodels
import plotly.io as pio
pio.renderers.default = 'notebook'
# Load and process data (same as before)
bank1_df = pd.read_csv("world_bank_definitive.csv")
crime_df = pd.read_csv("europe_crime_definitive_per_100k.csv")
bank_df = bank1_df[bank1_df['Indicator Name'] == "GDP per capita, PPP (constant 2021 international $)"]
bank_df = bank_df.rename(columns={"Value": "GDP per capita, PPP (constant 2021 international $)"})
crime_columns = [col for col in crime_df.columns if col not in ["Country Name", "Year", "geo"]]
crime_df["Total Crime Rate per 100k"] = crime_df[crime_columns].sum(axis=1)
merged_df = pd.merge(
crime_df[["Country Name", "Year", "Total Crime Rate per 100k"]],
bank_df[["Country Name", "Year", "GDP per capita, PPP (constant 2021 international $)"]],
on=["Country Name", "Year"]
)
# Create scatter plot with trendline
fig = px.scatter(
merged_df,
x="GDP per capita, PPP (constant 2021 international $)",
y="Total Crime Rate per 100k",
hover_name="Country Name",
hover_data={"Year": True},
trendline="ols", # Ordinary Least Squares regression line
title="GDP per Capita vs. Total Crime Rate per 100k"
)
fig.update_layout(
xaxis_title="GDP per capita, PPP (constant 2021 international $)",
yaxis_title="Total Crime Rate per 100k"
)
fig.show()
Het gemiddelde vermogen per persoon in een land in dollars tegen over het totaal aantal misdaden per land. Elk land is voor elk jaar dat het voorkomt in onze dataset weergegeven. Hover om de exacte waarden, het land en het jaar te zien van het datapunt
Het zou mogelijk kunnen zijn dat rijkere landen meer geldmiddelen hebben om criminelen te pakken en om te besteden aan handhaving/politie en dat daardoor het aantal geregistreerde misdaden hoger is, terwijl er niet perse meer misdaden gebeuren. Een andere mogelijke verklaring is dat criminelen meer toegang hebben tot middelen om misdaden te plegen en daardoor eerder geneigd te zijn om misdaden te plegen.
The Second Argument of Your Second Perspective#
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Show code cell source
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.io as pio
import pycountry
pio.renderers.default = 'notebook'
# === Load GINI Data ===
gini_df = pd.read_csv("gini_definitive.csv")
gini_df['Year'] = gini_df['Year'].astype(int)
# === Load Theft Data ===
theft_df = pd.read_csv("europe_crime_definitive_absolute.csv")
theft_df.rename(columns={'geo': 'Country Code', 'TIME_PERIOD': 'Year'}, inplace=True)
# Convert ISO-2 to ISO-3
def convert_iso2_to_iso3(code):
try:
return pycountry.countries.get(alpha_2=code).alpha_3
except:
return None
theft_df['Country Code'] = theft_df['Country Code'].apply(convert_iso2_to_iso3)
# Manual fixes for special regions/countries
manual_fix = {
'England and Wales': 'GBR',
'Northern Ireland (UK) (NUTS 2021)': 'GBR',
'Scotland (NUTS 2021)': 'GBR',
'Greece': 'GRC',
'Kosovo*': 'XKX'
}
theft_df['Country Code'] = theft_df.apply(
lambda row: manual_fix[row['Geopolitical entity (reporting)']]
if pd.isnull(row['Country Code']) and row['Geopolitical entity (reporting)'] in manual_fix
else row['Country Code'],
axis=1
)
theft_df['Year'] = theft_df['Year'].astype(int)
theft_df['Theft'] = pd.to_numeric(theft_df['Theft'], errors='coerce').fillna(0)
# === Years intersection and max year 2022 ===
years = sorted(list(set(gini_df['Year']).intersection(set(theft_df['Year']))))
years = [year for year in years if year <= 2022]
# Create subplot
fig = make_subplots(
rows=1, cols=2,
specs=[[{'type': 'choropleth'}, {'type': 'choropleth'}]],
subplot_titles=('GINI Index', 'Theft Incidents')
)
# Define color scales
gini_min, gini_max = gini_df['Value'].min(), gini_df['Value'].max()
theft_min, theft_max = theft_df['Theft'].min(), theft_df['Theft'].max()
# Add base traces (Year = first year)
fig.add_trace(
go.Choropleth(
locations=gini_df[gini_df['Year'] == years[0]]['Country Code'],
z=gini_df[gini_df['Year'] == years[0]]['Value'],
text=gini_df[gini_df['Year'] == years[0]]['Country Name'],
colorscale='Viridis',
zmin=gini_min,
zmax=gini_max,
colorbar=dict(title='GINI', x=0.45) # position colorbar left
),
row=1, col=1
)
fig.add_trace(
go.Choropleth(
locations=theft_df[theft_df['Year'] == years[0]]['Country Code'],
z=theft_df[theft_df['Year'] == years[0]]['Theft'],
text=theft_df[theft_df['Year'] == years[0]]['Geopolitical entity (reporting)'],
colorscale='Reds',
zmin=theft_min,
zmax=theft_max,
colorbar=dict(title='Theft', x=1.0) # position colorbar right
),
row=1, col=2
)
# Animation frames
frames = []
for year in years:
frame = go.Frame(
data=[
go.Choropleth(
locations=gini_df[gini_df['Year'] == year]['Country Code'],
z=gini_df[gini_df['Year'] == year]['Value'],
text=gini_df[gini_df['Year'] == year]['Country Name']
),
go.Choropleth(
locations=theft_df[theft_df['Year'] == year]['Country Code'],
z=theft_df[theft_df['Year'] == year]['Theft'],
text=theft_df[theft_df['Year'] == year]['Geopolitical entity (reporting)']
)
],
name=str(year)
)
frames.append(frame)
# Update layout
fig.update_layout(
title_text='GINI Index and Theft Incidents in Europe per Year',
title_x=0.5,
geo=dict(
showframe=False,
showcoastlines=True,
lataxis_range=[30, 72],
lonaxis_range=[-25, 45],
projection_type='natural earth'
),
geo2=dict( # for the 2nd map
showframe=False,
showcoastlines=True,
lataxis_range=[30, 72],
lonaxis_range=[-25, 45],
projection_type='natural earth'
),
sliders=[{
"steps": [{
"args": [[str(year)], {"frame": {"duration": 500, "redraw": True}, "mode": "immediate"}],
"label": str(year),
"method": "animate"
} for year in years],
"transition": {"duration": 300},
"x": 0.1,
"len": 0.8
}],
updatemenus=[{
"buttons": [{
"args": [None, {"frame": {"duration": 500, "redraw": True}, "fromcurrent": True}],
"label": "Play",
"method": "animate"
}, {
"args": [[None], {"frame": {"duration": 0}, "mode": "immediate"}],
"label": "Pause",
"method": "animate"
}],
"direction": "left",
"pad": {"r": 10, "t": 70},
"showactive": False,
"type": "buttons",
"x": 0.1,
"xanchor": "right",
"y": 0,
"yanchor": "top"
}]
)
fig.frames = frames
fig.show()
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[5], line 6
4 from plotly.subplots import make_subplots
5 import plotly.io as pio
----> 6 import pycountry
8 pio.renderers.default = 'notebook'
10 # === Load GINI Data ===
ModuleNotFoundError: No module named 'pycountry'
Figure 5: ddd
ddd
Show code cell source
import pandas as pd
import plotly.express as px
import random
Figure 6: blabla
Reflection#
d
Work Distribution#
Jason richtte zich op het preprocessen van de datasets. Hierna focusde hij zich vooral op het coordineren van de samenwerking en begeleidende tekst voor het datastory.
References#
De Courson, B., Nettle, D. Why do inequality and deprivation produce high crime and low trust?. Sci Rep 11, 1937 (2021). https://doi.org/10.1038/s41598-020-80897-8